package be.sc.classicnetwork.model;

import java.io.Serializable;
import java.util.Date;
import java.util.UUID;

import javax.persistence.GeneratedValue;
import javax.persistence.Id;
import javax.persistence.MappedSuperclass;
import javax.persistence.Transient;
import javax.persistence.Version;

import org.apache.commons.lang.builder.EqualsBuilder;
import org.apache.commons.lang.builder.HashCodeBuilder;
import org.apache.log4j.Logger;
import org.hibernate.annotations.GenericGenerator;
import org.hibernate.validator.ClassValidator;
import org.hibernate.validator.InvalidValue;

/**
 * Super class for entities. Specifies an id and a version attribute for
 * optimistic locking purpose.
 */
@MappedSuperclass
public abstract class AbstractEntity implements Serializable {
    @Transient
    protected final Logger log = Logger.getLogger(this.getClass());

    /** Primary key */
    @Id
    @GeneratedValue(generator = "system-uuid")
    @GenericGenerator(name = "system-uuid", strategy = "uuid")
    private String id;

    /** Version attribute for optimistic locking */
    @Version
    private Integer version = 0;

    private Date createdDate;

    private Date lastSavedDate;

    private String createdBy;

    private UserInfo userInfo = new UserInfo();

    /**
     * Creates a default AbstractEntity.
     */
    public AbstractEntity() {
	super();
    }

    /**
     * Checks this entity hasn't been saved yet.
     */
    public boolean isNew() {
	return (id == null);
    }

    /**
     * Generates a unique id.
     * 
     * @see UUID
     */
    public void generateId() {
	this.id = UUID.randomUUID().toString();
    }

    /**
     * Validate this entity with the annotated hibernate validators.
     * 
     * @throws IllegalStateException
     *                 if an attribute is invalide
     */
    @SuppressWarnings("unchecked")
    public void validate() {
	ClassValidator classValidator = new ClassValidator(this.getClass());
	InvalidValue[] invalidValues = classValidator.getInvalidValues(this);
	if ((invalidValues != null) && (invalidValues.length > 0)) {
	    throw new IllegalStateException(invalidValues[0].getMessage());
	}
    }

    /**
     * Creates an AbstractEntity with the specified id.
     * 
     * @param id
     */
    public AbstractEntity(String id) {
	this.id = id;
    }

    /**
     * @see java.lang.Object#equals(java.lang.Object)
     */
    @Override
    public boolean equals(Object anObject) {
	if (anObject instanceof AbstractEntity == false) {
	    return false;
	}
	if (this == anObject) {
	    return true;
	}
	AbstractEntity abstractEntity = (AbstractEntity) anObject;
	if (id == null && abstractEntity.getId() == null) {
	    return false;
	}
	return new EqualsBuilder().append(id, abstractEntity.getId()).isEquals();
    }

    /**
     * @see java.lang.Object#hashCode()
     */
    @Override
    public int hashCode() {
	return new HashCodeBuilder().append(id).toHashCode();
    }

    /**
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
	return String.valueOf(id);
    }

    public String getId() {
	return id;
    }

    public void setId(String id) {
	this.id = id;
    }

    public Integer getVersion() {
	return version;
    }

    public void setVersion(Integer version) {
	this.version = version;
    }

    public Date getCreatedDate() {
	return createdDate;
    }

    public void setCreatedDate(Date createdDate) {
	this.createdDate = createdDate;
    }

    public Date getLastSavedDate() {
	return lastSavedDate;
    }

    public void setLastSavedDate(Date lastSavedDate) {
	this.lastSavedDate = lastSavedDate;
    }

    public String getCreatedBy() {
	return createdBy;
    }

    public void setCreatedBy(String createdBy) {
	this.createdBy = createdBy;
    }

    public UserInfo getUserInfo() {
	return userInfo;
    }

    public void setUserInfo(UserInfo userInfo) {
	this.userInfo = userInfo;
    }

}
